package chen.web.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ContentFilter {
	
	public static String escapeXml(String str){
		if(str == null){
			return null;
		}
		StringBuffer sb = new StringBuffer();
		for(int i=0; i<str.length(); i++){
			char c = str.charAt(i);
			if(c == '<'){
				sb.append("&lt;");
			} else if(c == '>'){
				sb.append("&gt;");
			} else{
				sb.append(c);
			}
		}
		return sb.toString();
	}
	
	private static Pattern htmlPattern = Pattern.compile("<.+?>");
	public static String removeHtml(String html){
	    Matcher m = htmlPattern.matcher(html);
	    String result = m.replaceAll("");
	    return result;
	}
	
	private static Pattern ubbPattern = Pattern.compile("[.+?]");
	public static String removeUbb(String ubb){
	    Matcher m = ubbPattern.matcher(ubb);
	    String result = m.replaceAll("");
	    return result;
	}

	/**
	 * 移除html字符串中的脚本，另外禁止style,iframe,frameset,script等标签
	 * @param str
	 * @return
	 */
	public static String escapeScript(final String str){
		if (str.length() == 0) {
			return str;
		}
		StringBuffer builder = new StringBuffer(str.length() * 2);
		int length = str.length();
		main:for(int i=0; i<length; i++){
			char c = str.charAt(i);
			//html标签
			if(c == '<'){
				//过滤开始标签
				if(i+1 < length && str.charAt(i+1) != '/'){
					for(int j=i+1; j<length; j++){
						char ch = str.charAt(j);
						if(ch == '>'){
							if((str.charAt(j-1) == '/' && !isSafe(str, i+1, j-2)) || (str.charAt(j-1) != '/' && !isSafe(str, i+1, j))){
								for(int k=i; k<=j;k++){
									char t = str.charAt(k);
									if(t == '<'){
										builder.append("&lt;");
									} else if(t == '>'){
										builder.append("&gt;");
									} else {
										builder.append(t);	
									}
								}
								i=j;
								continue main;	
							}
							break;
						}
					}
				}
			}
			builder.append(c);	
		}
		return builder.toString();
	}
	
	private static boolean isSafe(String str, int begin, int end){
		//过滤标签
		if(isMatch(str, "style", begin) || isMatch(str, "script", begin) || isMatch(str, "iframe", begin) || isMatch(str, "frameset", begin)){
			return false;
		}
		for(int i=begin; i<=end; i++){
			char ch = str.charAt(i);
			//过滤特殊字符
			if(ch=='*' || ch=='<' || ch=='\\'){
				return false;
			}
			//过滤style中的expression
			if((ch=='e' || ch=='E') && isMatch(str, "expression", i)){
				return false;
			}
			//过滤a标签中的javascript,vbscript
			if((ch=='s' || ch=='S') && isMatch(str, "script", i) && (str.charAt(begin)=='a' || str.charAt(begin)=='A')){
				for(int j=i;j<end;j++){
					//有冒号
					if(j==':'){
						return false;
					}
				}
			}
			//过滤事件
			if((ch=='o' || ch=='O') && isMatch(str, "on", i)){
				if(i+2<end && i-1>begin){
					char after = str.charAt(i+2);
					char before = str.charAt(i-1);
					//on之后的字符是字母，之前的字符不是字母和数字
					if(Character.isLetter(after) && !Character.isLetterOrDigit(before)){
						//后面有等号
						for(int j=i; j<end; j++){
							if(j=='='){
								return false;
							}
						}
					}
				}
			}
			//过滤style中的url引用
			if((ch=='u'||ch=='U') && isMatch(str, "url", i)){
				if(i+3<end && i-1>begin){
					char after = str.charAt(i+3);
					char before = str.charAt(i-1);
					//url之后的字符是字母或数字，之前的字符不是字母或数字
					if(!Character.isLetterOrDigit(after) && !Character.isLetterOrDigit(before)){
						return false;
					}
				}
			}
		}
		return true;
	}
	
	
	/**
	 * 从指定的位置开始匹配，判断是否匹配，忽略字母大小写
	 * @param resource
	 * @param matchStr
	 * @param begin
	 * @return
	 */
	private static boolean isMatch(String resource, String matchStr, int begin){
		for(int i=0; i<matchStr.length(); i++){
			if(begin == resource.length()){
				return false;
			}
			char ch = matchStr.charAt(i);
			int index = resource.indexOf(ch, begin);
			//若不匹配，忽略字母大小写后，再匹配一次
			if(index != begin){
				if(ch > 64 && ch < 91){
					ch = (char)(ch + 32);
				} else if(ch >96 && ch < 123){
					ch = (char)(ch - 32);
				}
				index = resource.indexOf(ch, begin);
				if(index != begin) {
					return false;
				}
				return false;
			}
			begin = begin + 1;
		}
		return true;
	}
}
